import { DeviceEventEmitter } from 'react-native';
import { NavigationActions } from 'react-navigation';

import { Post, PostByShortConnection } from '../service/ShellExec';
import { ErrOk, ErrServer } from './errorCode';
import { toolTipOpen, loading } from '../util/global';
import navigator from '../util/navigator';
import { clearUserInfo, getUserInfo } from '../store/user';
import MockData from '../mock';
import { destroyEngine, leaveChannel } from '../util/RTC/rtcEngine';
import { EVENT_KICKED_OUT } from '../constant';
import tracker from '../util/actionTracker';
import { requestError, requestTimeout } from '../constant/events';
import { netSpeed } from '../util/native';

export interface Param {
  isMock?: boolean; // 是否使用mock数据
  needUserId?: boolean; // 是否需要userId
  needLoading?: boolean; // 请求是否需要loading
  needToast?: boolean; // 请求失败是否需要提示
  limitFrequency?: boolean; // 是否需要雪崩检测
}

interface Params {
  [key: string]: any;
}

interface Request {
  msgId: number;
  param?: Param;
  data?: Params;
}

export default ({ msgId, data = {}, param = {} }: Request): Promise<any> => {
  const {
    needLoading = false,
    needToast = true,
    isMock = false,
    needUserId,
    limitFrequency = true
  } = param;

  if (needLoading) {
    loading.show();
  }

  let params = data;

  if (needUserId) {
    const { userId } = getUserInfo();
    params = {
      ...params,
      userId
    };
  }

  const startSt = +new Date();
  const startTotalBytes = netSpeed.getTotalRxBytes();
  const startAppBytes = netSpeed.getUidRxBytes(0);

  return new Promise((resolve, reject): void => {
    if (isMock) {
      setTimeout((): void => {
        const res = MockData[msgId];
        resolve(res);
        if (needLoading) {
          loading.hide();
        }
      }, 1000);
      return;
    }

    // Post(msgId, params, limitFrequency)

    PostByShortConnection(msgId, params)
      .then((res): void => {
        if (needLoading) {
          loading.hide();
        }

        const endSt = +new Date();
        const duration = endSt - startSt;
        if (duration > 1000) {
          const endTotalBytes = netSpeed.getTotalRxBytes();
          const endAppBytes = netSpeed.getUidRxBytes(0);
          const totalBytes = endTotalBytes - startTotalBytes;
          const appBytes = endAppBytes - startAppBytes;
          tracker.reportAction(requestTimeout, {
            reason: JSON.stringify({
              msgId,
              params,
              duration,
              totalSpeed: netSpeed.getNetSpeed(totalBytes, duration),
              appSpeed: netSpeed.getNetSpeed(appBytes, duration)
            })
          });
        }

        if (res.code === 107 || res.code === 1004) {
          toolTipOpen({
            desc: '登录信息失效，请重新登录！'
          });
          setTimeout((): void => {
            clearUserInfo();
            leaveChannel({});
            destroyEngine();
            DeviceEventEmitter.emit(EVENT_KICKED_OUT, {});
            navigator.reset([
              NavigationActions.navigate({
                routeName: 'Login'
              })
            ]);
          });
          resolve(res);
          return;
        }
        if (res.code !== ErrOk && needToast) {
          if (res.code === ErrServer) {
            toolTipOpen({
              desc: '系统错误'
            });
          } else {
            toolTipOpen({
              desc: res.msg
            });
          }
        }
        resolve(res);
      })
      .catch((err): void => {
        if (needLoading) {
          loading.hide();
        }

        console.log('post', err);

        if (needToast) {
          toolTipOpen({
            desc: '网络超时，请稍后重试'
          });
        }

        const endSt = +new Date();
        const duration = endSt - startSt;
        const endTotalBytes = netSpeed.getTotalRxBytes();
        const endAppBytes = netSpeed.getUidRxBytes(0);
        const totalBytes = endTotalBytes - startTotalBytes;
        const appBytes = endAppBytes - startAppBytes;
        tracker.reportAction(requestError, {
          reason: JSON.stringify({
            msgId,
            params,
            error: err,
            duration,
            totalSpeed: netSpeed.getNetSpeed(totalBytes, duration),
            appSpeed: netSpeed.getNetSpeed(appBytes, duration)
          })
        });

        reject(err);
      });
  });
};
